using System;
using System.Collections.Generic;
using Xunit;
using WenYu.Core.Lexer;
using WenYu.Core.Parser;

namespace WenYu.Tests.DocumentValidation;

/// <summary>
/// 文档06-类与对象.md的示例验证测试
/// </summary>
public class Doc06ClassesAndObjectsValidation
{
    private List<Token> Tokenize(string source)
    {
        var lexer = new WenYuLexer(source);
        return lexer.Tokenize();
    }

    private Program Parse(string source)
    {
        var lexer = new WenYuLexer(source);
        var tokens = lexer.Tokenize();
        var parser = new WenYuParser(tokens);
        return parser.Parse();
    }

    #region 类定义测试

    [Fact]
    public void Example1_SimpleClass()
    {
        var source = @"车 是 类，含 整型 价格。";

        var tokens = Tokenize(source);
        Assert.NotEmpty(tokens);

        var tokenValues = new List<string>();
        foreach (var token in tokens)
        {
            if (!string.IsNullOrWhiteSpace(token.Value))
                tokenValues.Add(token.Value);
        }

        Assert.Contains("是", tokenValues);
        Assert.Contains("类", tokenValues);
        Assert.Contains("含", tokenValues);

        var ast = Parse(source);
        Assert.NotNull(ast);
    }

    [Fact]
    public void Example2_MultiAttributeClass()
    {
        var source = @"车 是 类，含{
    整型 价格。
    文字 品牌。
    文字 颜色。
}";

        var tokens = Tokenize(source);
        Assert.NotEmpty(tokens);
        var ast = Parse(source);
        Assert.NotNull(ast);
    }

    [Fact]
    public void Example3_ClassWithDefaults()
    {
        var source = @"车 是 类，含{
    整型 价格 是 10。
    文字 品牌 是 ""未知""。
    文字 颜色 是 ""白色""。
}";

        var tokens = Tokenize(source);
        Assert.NotEmpty(tokens);
        var ast = Parse(source);
        Assert.NotNull(ast);
    }

    #endregion

    #region 对象创建和属性访问测试

    [Fact]
    public void Example4_CreateAndAccessObject()
    {
        var source = @"车 是 类，含{
    整型 价格。
    文字 品牌。
}

车 宝马 的 价格 是 23。
车 宝马 的 品牌 是 ""BMW""。

整型 价钱 是 宝马的价格。
输出（价钱的文字）。";

        var tokens = Tokenize(source);
        Assert.NotEmpty(tokens);

        var tokenValues = new List<string>();
        foreach (var token in tokens)
        {
            if (!string.IsNullOrWhiteSpace(token.Value))
                tokenValues.Add(token.Value);
        }

        Assert.Contains("的", tokenValues);

        var ast = Parse(source);
        Assert.NotNull(ast);
    }

    [Fact]
    public void Example5_ModifyProperty()
    {
        var source = @"车 是 类，含 整型 价格。

车 宝马 的 价格 是 23。
输出（宝马的价格的文字）。

宝马的价格 是 25。
输出（宝马的价格的文字）。";

        var tokens = Tokenize(source);
        Assert.NotEmpty(tokens);
        var ast = Parse(source);
        Assert.NotNull(ast);
    }

    [Fact]
    public void Example6_PropertyInExpression()
    {
        var source = @"车 是 类，含 整型 价格。

车 宝马 的 价格 是 23。
车 奔驰 的 价格 是 34。

整型 总价 是 宝马的价格 + 奔驰的价格。
输出（""总价："" + 总价的文字 + ""万""）。

若 宝马的价格 《 奔驰的价格 则{
    输出（""宝马更便宜""）。
}";

        var tokens = Tokenize(source);
        Assert.NotEmpty(tokens);
        var ast = Parse(source);
        Assert.NotNull(ast);
    }

    #endregion

    #region 完整示例测试

    [Fact]
    public void Example7_VehicleManagement()
    {
        var source = @"车 是 类，含{
    整型 价格。
    文字 品牌。
    文字 颜色。
}

车 宝马 的 价格 是 23。
车 宝马 的 品牌 是 ""BMW""。
车 宝马 的 颜色 是 ""白色""。

车 奔驰 的 价格 是 34。
车 奔驰 的 品牌 是 ""Benz""。
车 奔驰 的 颜色 是 ""黑色""。

输出（""===车辆信息===""）。
输出（""宝马："" + 宝马的品牌 + ""，"" + 宝马的颜色 + ""，"" + 宝马的价格的文字 + ""万""）。
输出（""奔驰："" + 奔驰的品牌 + ""，"" + 奔驰的颜色 + ""，"" + 奔驰的价格的文字 + ""万""）。

整型 总价 是 宝马的价格 + 奔驰的价格。
输出（""总价值："" + 总价的文字 + ""万""）。";

        var tokens = Tokenize(source);
        Assert.NotEmpty(tokens);
        var ast = Parse(source);
        Assert.NotNull(ast);
    }

    [Fact]
    public void Example8_StudentGradeManagement()
    {
        var source = @"学生 是 类，含{
    文字 姓名。
    整型 数学。
    整型 语文。
    整型 英语。
}

学生 小明 的 姓名 是 ""小明""。
学生 小明 的 数学 是 85。
学生 小明 的 语文 是 92。
学生 小明 的 英语 是 78。

学生 小红 的 姓名 是 ""小红""。
学生 小红 的 数学 是 95。
学生 小红 的 语文 是 88。
学生 小红 的 英语 是 90。

整型 小明总分 是 小明的数学 + 小明的语文 + 小明的英语。
整型 小红总分 是 小红的数学 + 小红的语文 + 小红的英语。

输出（""===成绩单===""）。
输出（小明的姓名 + ""：""）。
输出（""  数学："" + 小明的数学的文字）。
输出（""  语文："" + 小明的语文的文字）。
输出（""  英语："" + 小明的英语的文字）。
输出（""  总分："" + 小明总分的文字）。

若 小明总分 》 小红总分 则{
    输出（小明的姓名 + "" 总分更高！""）。
}余{
    输出（小红的姓名 + "" 总分更高！""）。
}";

        var tokens = Tokenize(source);
        Assert.NotEmpty(tokens);
        var ast = Parse(source);
        Assert.NotNull(ast);
    }

    [Fact]
    public void Example9_ProductWithDefaults()
    {
        var source = @"商品 是 类，含{
    文字 名称 是 ""未命名""。
    实型 单价 是 0.0。
    整型 数量 是 0。
}

商品 苹果 的 名称 是 ""红富士苹果""。
商品 苹果 的 单价 是 5.5。
商品 苹果 的 数量 是 10。

商品 神秘商品。

输出（苹果的名称 + ""：""）。
输出（""  单价："" + 苹果的单价的文字 + ""元""）。
输出（""  数量："" + 苹果的数量的文字）。

输出（""神秘商品："" + 神秘商品的名称）。";

        var tokens = Tokenize(source);
        Assert.NotEmpty(tokens);
        var ast = Parse(source);
        Assert.NotNull(ast);
    }

    [Fact]
    public void Example10_PromotionalDiscount()
    {
        var source = @"商品 是 类，含{
    文字 名称。
    实型 原价。
    实型 现价。
}

商品 手机 的 名称 是 ""智能手机""。
商品 手机 的 原价 是 2999.0。
商品 手机 的 现价 是 2999.0。

输出（""===双十一促销===""）。
输出（手机的名称 + "" 原价："" + 手机的原价的文字 + ""元""）。

若 手机的原价 》 2000.0 则{
    手机的现价 是 手机的原价 * 0.8。
    实型 优惠 是 手机的原价 - 手机的现价。
    
    输出（""享受8折优惠！""）。
    输出（""现价："" + 手机的现价的文字 + ""元""）。
    输出（""节省："" + 优惠的文字 + ""元""）。
}余{
    输出（""现价："" + 手机的现价的文字 + ""元""）。
}";

        var tokens = Tokenize(source);
        Assert.NotEmpty(tokens);
        var ast = Parse(source);
        Assert.NotNull(ast);
    }

    [Fact]
    public void Example11_KeywordRecognition()
    {
        var source = @"学生 是 类，含 文字 姓名。

学生 张三 的 姓名 是 ""张三""。
文字 名 是 张三的姓名。";

        var tokens = Tokenize(source);
        Assert.NotEmpty(tokens);

        var tokenValues = new List<string>();
        foreach (var token in tokens)
        {
            if (!string.IsNullOrWhiteSpace(token.Value))
                tokenValues.Add(token.Value);
        }

        // Verify class keywords are recognized
        Assert.Contains("是", tokenValues);
        Assert.Contains("类", tokenValues);
        Assert.Contains("含", tokenValues);
    }

    #endregion
}
